
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>

#include "track.h"
#include "gesture.h"
#include <tslib.h>

// TODO： 根据触摸屏分辨率的大小设置阈值
#define SLIDE_THRES 50
#define SCALE_THRES 50

static TouchPoint *touch_points = NULL;
static int *vaild_index = NULL;

static int cnt = 0;       // 当前触点数量
static int max_slots = 0; // 触摸屏支持的最大触点数量

static int pre_dis = -1;    // 记录两个触点上一次的距离

static long calculate_time_interval_ms(struct timeval start, struct timeval end)
{
    // 计算秒和微秒的差值
    long seconds, microseconds, milliseconds;

    seconds = end.tv_sec - start.tv_sec;
    microseconds = end.tv_usec - start.tv_usec;

    if (microseconds < 0)
    {
        seconds -= 1;
        microseconds += 1000000;
    }

    // 将秒转换为毫秒，并加上微秒转换为毫秒的部分
    milliseconds = seconds * 1000 + microseconds / 1000;

    return milliseconds;
}

static int distance(int x1, int y1, int x2, int y2)
{
    int l, h;
    l = x1 - x2;
    h = y1 - y2;
    return l * l + h * h;
}

static int angle(TouchPoint *tp)
{
    int l, h;
    int azi;

    l = tp->x - tp->start_x;
    h = tp->y - tp->start_y;

    //printf("l : %d h : %d\n",l,h);
    azi = atan2(h, l) * 180 / 3.14;
    return azi;
}

int init_touch_points(int slots_num)
{
    max_slots = slots_num;

    touch_points = (TouchPoint *)malloc(sizeof(TouchPoint) * slots_num);
    if (touch_points == NULL)
    {
        printf("Failed to allocate memory for touch points");
        return -1;
    }

    vaild_index = (int *)malloc(slots_num * sizeof(int));
    if (touch_points == NULL)
    {
        printf("Failed to allocate memory for vaild_index");
        return -1;
    }

    memset(touch_points, 0, sizeof(TouchPoint) * slots_num);
    for (int i = 0; i < max_slots; i++)
    {
        touch_points[i].vaild = false;
        touch_points[i].start_x = -1;
        touch_points[i].start_y = -1;
    }

    return 0;
}

void exit_touch_points(void)
{
    // 将之前动态申请的变量释放掉
    if (touch_points != NULL)
    {
        free(touch_points);
        touch_points = NULL;
    }
    if (vaild_index != NULL)
    {
        free(vaild_index);
        vaild_index = NULL;
    }
    cnt = 0;
}

static void update_touch(struct ts_sample_mt **samp_mt)
{
    int i, j;
    bool exits;
    int index;

    struct timeval tv;

    for (i = 0; i < max_slots; i++)
    {
        exits = false;
        if (samp_mt[0][i].valid)
        {
            // 判断当前触点是否已存在
            index = samp_mt[0][i].slot;
            exits = touch_points[index].vaild;

            if (exits) // 如果当前触点存在，则更新当前触点信息
            {
                // printf("exit\n");
                touch_points[index].x = samp_mt[0][i].x;
                touch_points[index].y = samp_mt[0][i].y;
                touch_points[index].tracking_id = samp_mt[0][i].tracking_id;
            }
            else // 否则新增触点
            {
                // printf("Not exit\n");
                touch_points[index].vaild = true;
                touch_points[index].slot = samp_mt[0][i].slot;
                touch_points[index].tracking_id = samp_mt[0][i].tracking_id;
                touch_points[index].x = samp_mt[0][i].x;
                touch_points[index].y = samp_mt[0][i].y;
                touch_points[index].start_x = samp_mt[0][i].x;
                touch_points[index].start_y = samp_mt[0][i].y;
                gettimeofday(&tv, NULL);
                touch_points[index].start_time = tv; // 保存当前触点按下的时间
                cnt++;                               // 触点计数加1
            }
        }
    }
}

// 这里也需要完成删除触摸点的功能
static void detect_gesture(void)
{
    int i;
    int real_num = 0; // 实际的触点
    long end_interval, start_interval;
    struct timeval curr_tv;
    int dis, azi;

    if (cnt == 0) // cnt只会比实际的触点多，如果cnt为0，那么则说明当前就没有触点
        return;

    for (i = 0; i < max_slots; i++)
    {
        if (touch_points[i].vaild)
        {
            if (touch_points[i].tracking_id > 0)
                vaild_index[real_num++] = i; // 记录实际有效的触点索引
            else
            {
                gettimeofday(&curr_tv, NULL);
                if (cnt == 1)
                {
                    start_interval = calculate_time_interval_ms(touch_points[i].start_time, curr_tv); // 触点从按下到松开的时间
                    end_interval = calculate_time_interval_ms(touch_points[i].end_time, curr_tv);     // 触点上一次松开到这一次松开的时间
                    //printf("%d  %d\n",start_interval,end_interval);
                    // 上一次触点松开的时间到现在松开小于500ms，则认为是双击。与上的第二个是为了确保在双击后又快速点击一下，不会被再次判断为双击
                    if (end_interval < 500 && touch_points[i].type != GESTURE_DOUBLE_TAP) 
                    {
                        touch_points[i].type = GESTURE_DOUBLE_TAP;
                        printf("双击\n");
                    }
                    else if (start_interval < 300)
                    {
                        touch_points[i].type = GESTURE_SINGLE_TAP;
                        printf("单击\n");
                    }
                }
                touch_points[i].end_time = curr_tv;
                touch_points[i].vaild = false;
                cnt--; // 触点计数减1
            }
        }
    }

    if(real_num != 2)
        pre_dis = -1;   //这个参数只有在双指缩放时才会用到，即需要是两个触点

    switch (real_num)
    {
        case 0: // 如果当前实际在按的触点数为0，则也直接返回
            return;
        case 1: // 当前有效触点数为1，则开始检测当前触点的移动距离和方向
        {
            dis = distance(touch_points[vaild_index[0]].x, touch_points[vaild_index[0]].y,
                                 touch_points[vaild_index[0]].start_x, touch_points[vaild_index[0]].start_y);
            if(dis > SLIDE_THRES * SLIDE_THRES)
            {
                // 这里是为了避免在双指缩放后，先抬起一个手指时，另外一个手指被判定为了单指滑动
                if(touch_points[vaild_index[0]].type == GESTURE_PINCH_IN || touch_points[vaild_index[0]].type == GESTURE_PINCH_OUT)
                {
                    touch_points[vaild_index[0]].type = GESTURE_NONE;
                    touch_points[vaild_index[0]].start_x = touch_points[vaild_index[0]].x;
                    touch_points[vaild_index[0]].start_y = touch_points[vaild_index[0]].y;
                    break;
                }
                
                // 计算当前的角度
                azi = angle(&touch_points[vaild_index[0]]);
                //printf("dis = %d, azi = %d\n", dis, azi);
                if (azi > -135 && azi < -45)
                {
                    touch_points[vaild_index[0]].type = GESTURE_SWIPE_UP;
                    printf("上滑\n");
                }
                else if (azi > 45 && azi < 135)
                {
                    touch_points[vaild_index[0]].type = GESTURE_SWIPE_DOWN;
                    printf("下滑\n");
                }
                else if(azi > -45 && azi < 45)
                {
                    touch_points[vaild_index[0]].type = GESTURE_SWIPE_RIGHT;
                    printf("右滑\n");
                }
                else
                {
                    touch_points[vaild_index[0]].type = GESTURE_SWIPE_LEFT;
                    printf("左滑\n");
                }
                // 更新起始位置为当前位置
                touch_points[vaild_index[0]].start_x = touch_points[vaild_index[0]].x;
                touch_points[vaild_index[0]].start_y = touch_points[vaild_index[0]].y;
            }
            break;
        }
        case 2: // 当前有效触点数为2，则开始检测是双指放大还是缩小
        {
            dis = distance(touch_points[vaild_index[0]].x, touch_points[vaild_index[0]].y,
                touch_points[vaild_index[1]].x, touch_points[vaild_index[1]].y);
            
            if(pre_dis < 0)
            {
                pre_dis = dis; 
            }
            else
            {
                if(dis > pre_dis + SCALE_THRES * SCALE_THRES)
                {
                    touch_points[vaild_index[0]].type = GESTURE_PINCH_OUT;
                    touch_points[vaild_index[1]].type = GESTURE_PINCH_OUT;
                    printf("双指放大\n");
                }
                else if(dis < pre_dis - SCALE_THRES * SCALE_THRES)
                {
                    touch_points[vaild_index[0]].type = GESTURE_PINCH_IN;
                    touch_points[vaild_index[1]].type = GESTURE_PINCH_IN;
                    printf("双指缩小\n");
                }
                pre_dis = dis; // 更新上一次的距离
            }
            break;
        }
        default:
        {
            printf("Now touch %d points\n", real_num);
            break;
        }
    }
}

void proc_gesture(struct ts_sample_mt **samp_mt)
{
    // printf("debug\n");
    update_touch(samp_mt);
    detect_gesture();
}
